//-----------------------------------------------------------------------------
//  Copyright (C) 2011-2018, GB Research, LLC (www.gbresearch.com)
//  
//  Boost Software License - Version 1.0 - August 17th, 2003
//
//  Permission is hereby granted, free of charge, to any person or organization
//  obtaining a copy of the software and accompanying documentation covered by
//  this license (the "Software") to use, reproduce, display, distribute,
//  execute, and transmit the Software, and to prepare derivative works of the
//  Software, and to permit third-parties to whom the Software is furnished to
//  do so, all subject to the following:
//
//  The copyright notices in the Software and this entire statement, including
//  the above license grant, this restriction and the following disclaimer,
//  must be included in all copies of the Software, in whole or in part, and
//  all derivative works of the Software, unless such copies or derivative
//  works are solely in the form of machine-executable object code generated by
//  a source language processor.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
//  SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
//  FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#pragma once

#include <type_traits>
#include <utility>
#include "axe_predicate.h"
#include "axe_trait.h"

namespace axe
{

    //-------------------------------------------------------------------------
    // operators and functions for predicates
    //-------------------------------------------------------------------------

    template<class P1, class P2>
    p_and_t<
        std::enable_if_t<AXE_IS_PREDICATE(P1), P1>,
        std::enable_if_t<AXE_IS_PREDICATE(P2), P2>
    >
        operator && (P1&& p1, P2&& p2)
    {
        return p_and_t<P1, P2>(std::forward<P1>(p1), std::forward<P2>(p2));
    }

    //-------------------------------------------------------------------------
    template<class P1, class P2>
    p_or_t<
        std::enable_if_t<AXE_IS_PREDICATE(P1), P1>,
        std::enable_if_t<AXE_IS_PREDICATE(P2), P2>
    >
        operator || (P1&& p1, P2&& p2)
    {
        return p_or_t<P1, P2>(std::forward<P1>(p1), std::forward<P2>(p2));
    }

    //-------------------------------------------------------------------------
    template<class P1, class P2>
    p_xor_t<
        std::enable_if_t<AXE_IS_PREDICATE(P1), P1>,
        std::enable_if_t<AXE_IS_PREDICATE(P2), P2>
    >
        operator ^ (P1&& p1, P2&& p2)
    {
        return p_xor_t<P1, P2>(std::forward<P1>(p1), std::forward<P2>(p2));
    }

    //-------------------------------------------------------------------------
    template<class P1>
    p_not_t<
        std::enable_if_t<AXE_IS_PREDICATE(P1), P1>
    >
        operator ! (P1&& p1)
    {
        return p_not_t<P1>(std::forward<P1>(p1));
    }

    //-------------------------------------------------------------------------
    /// is_char function matches a single character
    //-------------------------------------------------------------------------
    template<class CharT>
    inline is_char_t<CharT> is_char(CharT c) { return is_char_t<CharT>(c); }

    //-------------------------------------------------------------------------
    /// is_any function matches any characters in the range [c1, c2]
    //-------------------------------------------------------------------------
    template<class CharT>
    inline is_any_t<CharT> is_any(CharT c1, CharT c2) { return is_any_t<CharT>(c1, c2); }

    //-------------------------------------------------------------------------
    /// is_any function matches any characters present in the string
    //-------------------------------------------------------------------------
    template<class CharT>
    inline is_any_t<const CharT*> is_any(const CharT* str) { return is_any_t<const CharT*>(str); }

    //-------------------------------------------------------------------------
    /// is_any function matches any single character
    //-------------------------------------------------------------------------
    inline is_any_t<void> is_any() { return is_any_t<void>(); }
}
